let THREE=require('three');
import M from '../general/utils';
import OverlapPairs from './broad-component/overlap-pairs';
import ColliderDetection from './broad-component/collider-detection';
import CONST from './collision-const';
import SpatialPartitioningMethod from './broad-component/spatial-partitioning-method';

/**
 *空间分割检测
 * @param config {jCollisionWorldConfig}
 */
export default class BroadPhase{
    constructor(config={}){
        this._config=config;
        this._init();
    }

    //-----------------------------------------对外属性及方法-----------------------------------------

    /**
     * 设置碰撞进入的回调
     * @param func_collider
     */
    set onContactEnter(func_collider){
        this._onContactEnter=func_collider;
    }

    /**
     * 设置碰撞中的回调
     * @param func_collider
     */
    set onContactStay(func_collider){
        this._onContactStay=func_collider;
    }

    /**
     * 设置碰撞退出的回调
     * @param func_collider
     */
    set onContactExit(func_collider){
        this._onContactExit=func_collider;
    }

    /**
     * 更新形状并检测
     * @param colliders
     */
    updateCollider(...colliders){
        this._tree.updateCollider(...colliders);
        this._checkCollision();
    }

    /**
     * 添加形状
     * @param colliders
     */
    addCollider(...colliders){
        for(let s of colliders){
            let idx=this._colliders.findIndex((_s)=>_s.uuid===s.uuid);
            if(idx!==-1)return;
            this._colliders.push(s);
            this._tree.addCollider(s);
        }
    }

    /**
     * 移除形状
     * @param colliders
     */
    removeCollider(...colliders){
        for(let s of colliders){
            let idx=this._colliders.findIndex((_s)=>_s.uuid===s.uuid);
            if(idx===-1)return;
            this._tree.removeCollider(s);
            this._colliders.splice(idx,1);
        }
    }

    /**
     * 清除形状
     */
    clearCollider(){
        for(let s of this._colliders){
            this._tree.removeCollider(s);
        }
        this._colliders=[];
    }

    //--------------------------------------------私有属性及方法-------------------------------------------------

    /**
     * 检测交叠对的碰撞情况
     * @private
     */
    _checkCollision() {
        let pairs = this._overlaps.pairs;
        let nodes = this._tree.nodes;

        if(this._config.recordContactTarget) {
            nodes.forEach((n) => {
                if(n.collider)n.collider.resetContact();
            });
        }

        let na,nb,breakPoint=0;
        this._newContacts[breakPoint]=-1;
        for (let i = 0; i < pairs.length; i += 2) {
            if (pairs[i] < 0)break;
            na=nodes[pairs[i]].collider;
            nb=nodes[pairs[i + 1]].collider;
            if(!(na.enabled&&nb.enabled))continue;
            /**
             * 交叠对形状属于同一碰撞体则不进行下一步相交检测
             */
            if(na.userData.rigid.uuid===nb.userData.rigid.uuid){
                continue;
            }
            let bol=ColliderDetection.checkColliderPair(na,nb,this._contactPointOnA,this._contactPointOnB);
            if(bol){

                if(this._config.recordContactTarget) {
                    na.addContact(nb,this._contactPointOnA);
                    nb.addContact(na,this._contactPointOnB);
                }

                if(breakPoint>this._newContacts.length-4)this._increaseVolume();

                let hasA=false,hasB=false;
                for(let k=0;k<this._newContacts.length;k++){
                    if(this._newContacts[k]<0)break;
                    if(hasA&&hasB)break;
                    if(this._newContacts[k]===pairs[i])hasA=true;
                    if(this._newContacts[k]===pairs[i+1])hasB=true;
                }
                if(!hasA) {
                    this._newContacts[breakPoint] = pairs[i];
                    breakPoint++;
                }
                if(!hasB) {
                    this._newContacts[breakPoint] = pairs[i + 1];
                    breakPoint++;
                }
                this._newContacts[breakPoint]=-1;
            }
        }
        this._checkContactState(nodes);
        for(let i=0;i<this._newContacts.length;i++){
            if(this._newContacts[i]<0){
                this._oldContacts[i]=-1;
                break;
            }
            this._oldContacts[i]=this._newContacts[i];
        }
    }

    /**
     * 检测碰撞形状的碰撞状态
     * @param nodes
     * @private
     */
    _checkContactState(nodes){
        let shp=null;
        for(let i=0;i<this._newContacts.length;i++){
            if(this._newContacts[i]<0)break;
            let isExist=false;
            for(let j=0;j<this._oldContacts.length;j++){
                if(this._oldContacts[j]<0)break;
                if(this._newContacts[i]===this._oldContacts[j]){
                    isExist=true;
                    break;
                }
            }
            if(isExist){
                shp=nodes[this._newContacts[i]].collider;
                if(this._config.recordContactTarget)shp.confirmContact();
                if(this._onContactStay)this._onContactStay(shp);
            }else{
                shp=nodes[this._newContacts[i]].collider;
                if(this._config.recordContactTarget)shp.confirmContact();
                if(this._onContactEnter)this._onContactEnter(shp);
            }
        }
        for(let i=0;i<this._oldContacts.length;i++){
            if(this._oldContacts[i]<0)break;
            let isExist=false;
            for(let j=0;j<this._newContacts.length;j++){
                if(this._newContacts[j]<0)break;
                if(this._newContacts[j]===this._oldContacts[i]){
                    isExist=true;
                    break;
                }
            }
            if(!isExist){
                shp=nodes[this._oldContacts[i]].collider;
                if(this._config.recordContactTarget)shp.confirmContact();
                if(this._onContactExit)this._onContactExit(shp);
            }
        }
    }

    /**
     * 增加碰撞列表的容量
     * @private
     */
    _increaseVolume(){
        let nLen=this._newContacts.length*2;
        this._newContacts=M.resizeTypedArray(this._newContacts,nLen);
        this._oldContacts=M.resizeTypedArray(this._oldContacts,nLen);
    }

    /**
     * 初始化
     * @private
     */
    _init(){
        this._initVariable();
        this._initComponents();
        this._initialize();
    }

    /**
     * 初始化变量
     * @private
     */
    _initVariable(){
        this._colliders=[];
        this._tree=null;
        this._overlaps=null;
        this._newContacts=new Int16Array(64);
        this._newContactsBreak=0;
        this._newContacts[this._newContactsBreak]=-1;
        this._oldContacts=new Int16Array(64);
        this._oldContacts[0]=-1;

        this._onContactEnter=null;
        this._onContactStay=null;
        this._onContactExit=null;
        this._contactPointOnA=new THREE.Vector3();
        this._contactPointOnB=new THREE.Vector3();
    }

    /**
     * 初始化组件状态
     * @private
     */
    _initialize(){
        this._tree.overlaps=this._overlaps;
    }

    /**
     * 初始化组件
     * @private
     */
    _initComponents(){
        this._initTree();
        this._initOverlaps();
    }

    /**
     * 初始化分割检测实例
     * @private
     */
    _initTree(){
        switch (this._config.spatialPartitioningMethod){
            case CONST.SPATIAL_PARTITIONING_DBVT:
                this._tree=new SpatialPartitioningMethod.DBVT();
                break;
            case CONST.SPATIAL_PARTITIONING_SAP:
                this._tree=new SpatialPartitioningMethod.SAP();
                break;
            default:
                this._tree=new SpatialPartitioningMethod.DBVT();
                break;
        }
    }

    /**
     * 初始化交叠对记录器
     * @private
     */
    _initOverlaps(){
        this._overlaps=new OverlapPairs();
    }
}